package com.rainwen.el;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.math.BigDecimal;
import java.math.BigInteger;

public class ELSupport
{
  private static final Long ZERO = Long.valueOf(0L);
  
  public static final int compare(Object obj0, Object obj1)
    throws ELException
  {
    if ((obj0 == obj1) || (equals(obj0, obj1))) {
      return 0;
    }
    if (isBigDecimalOp(obj0, obj1))
    {
      BigDecimal bd0 = (BigDecimal)coerceToNumber(obj0, BigDecimal.class);
      BigDecimal bd1 = (BigDecimal)coerceToNumber(obj1, BigDecimal.class);
      return bd0.compareTo(bd1);
    }
    if (isDoubleOp(obj0, obj1))
    {
      Double d0 = (Double)coerceToNumber(obj0, Double.class);
      Double d1 = (Double)coerceToNumber(obj1, Double.class);
      return d0.compareTo(d1);
    }
    if (isBigIntegerOp(obj0, obj1))
    {
      BigInteger bi0 = (BigInteger)coerceToNumber(obj0, BigInteger.class);
      BigInteger bi1 = (BigInteger)coerceToNumber(obj1, BigInteger.class);
      return bi0.compareTo(bi1);
    }
    if (isLongOp(obj0, obj1))
    {
      Long l0 = (Long)coerceToNumber(obj0, Long.class);
      Long l1 = (Long)coerceToNumber(obj1, Long.class);
      return l0.compareTo(l1);
    }
    if (((obj0 instanceof String)) || ((obj1 instanceof String))) {
      return coerceToString(obj0).compareTo(coerceToString(obj1));
    }
    if ((obj0 instanceof Comparable))
    {
      Comparable<Object> comparable = (Comparable)obj0;
      return obj1 != null ? comparable.compareTo(obj1) : 1;
    }
    if ((obj1 instanceof Comparable))
    {
      Comparable<Object> comparable = (Comparable)obj1;
      return obj0 != null ? -comparable.compareTo(obj0) : -1;
    }
    throw new ELException(MessageFactory.get("error.compare", new Object[] { obj0, obj1 }));
  }
  
  public static final boolean equals(Object obj0, Object obj1)
    throws ELException
  {
    if (obj0 == obj1) {
      return true;
    }
    if ((obj0 == null) || (obj1 == null)) {
      return false;
    }
    if (isBigDecimalOp(obj0, obj1))
    {
      BigDecimal bd0 = (BigDecimal)coerceToNumber(obj0, BigDecimal.class);
      BigDecimal bd1 = (BigDecimal)coerceToNumber(obj1, BigDecimal.class);
      return bd0.equals(bd1);
    }
    if (isDoubleOp(obj0, obj1))
    {
      Double d0 = (Double)coerceToNumber(obj0, Double.class);
      Double d1 = (Double)coerceToNumber(obj1, Double.class);
      return d0.equals(d1);
    }
    if (isBigIntegerOp(obj0, obj1))
    {
      BigInteger bi0 = (BigInteger)coerceToNumber(obj0, BigInteger.class);
      BigInteger bi1 = (BigInteger)coerceToNumber(obj1, BigInteger.class);
      return bi0.equals(bi1);
    }
    if (isLongOp(obj0, obj1))
    {
      Long l0 = (Long)coerceToNumber(obj0, Long.class);
      Long l1 = (Long)coerceToNumber(obj1, Long.class);
      return l0.equals(l1);
    }
    if (((obj0 instanceof Boolean)) || ((obj1 instanceof Boolean))) {
      return coerceToBoolean(obj0).equals(coerceToBoolean(obj1));
    }
    if (obj0.getClass().isEnum()) {
      return obj0.equals(coerceToEnum(obj1, obj0.getClass()));
    }
    if (obj1.getClass().isEnum()) {
      return obj1.equals(coerceToEnum(obj0, obj1.getClass()));
    }
    if (((obj0 instanceof String)) || ((obj1 instanceof String)))
    {
      int lexCompare = coerceToString(obj0).compareTo(coerceToString(obj1));
      return lexCompare == 0;
    }
    return obj0.equals(obj1);
  }
  
  public static final Enum<?> coerceToEnum(Object obj, Class type)
  {
    if ((obj == null) || ("".equals(obj))) {
      return null;
    }
    if (type.isAssignableFrom(obj.getClass())) {
      return (Enum)obj;
    }
    if (!(obj instanceof String)) {
      throw new ELException(MessageFactory.get("error.convert", new Object[] { obj, obj.getClass(), type }));
    }
    Enum<?> result;
    try
    {
      result = Enum.valueOf(type, (String)obj);
    }
    catch (IllegalArgumentException iae)
    {
      throw new ELException(MessageFactory.get("error.convert", new Object[] { obj, obj.getClass(), type }));
    }
    return result;
  }
  
  public static final Boolean coerceToBoolean(Object obj)
    throws ELException
  {
    if ((obj == null) || ("".equals(obj))) {
      return Boolean.FALSE;
    }
    if ((obj instanceof Boolean)) {
      return (Boolean)obj;
    }
    if ((obj instanceof String)) {
      return Boolean.valueOf((String)obj);
    }
    throw new ELException(MessageFactory.get("error.convert", new Object[] { obj, obj.getClass(), Boolean.class }));
  }
  
  public static final Character coerceToCharacter(Object obj)
    throws ELException
  {
    if ((obj == null) || ("".equals(obj))) {
      return Character.valueOf('\000');
    }
    if ((obj instanceof String)) {
      return Character.valueOf(((String)obj).charAt(0));
    }
    if (ELArithmetic.isNumber(obj)) {
      return Character.valueOf((char)((Number)obj).shortValue());
    }
    Class<?> objType = obj.getClass();
    if ((obj instanceof Character)) {
      return (Character)obj;
    }
    throw new ELException(MessageFactory.get("error.convert", new Object[] { obj, objType, Character.class }));
  }
  
  protected static final Number coerceToNumber(Number number, Class<?> type)
    throws ELException
  {
    if ((Long.TYPE == type) || (Long.class.equals(type))) {
      return Long.valueOf(number.longValue());
    }
    if ((Double.TYPE == type) || (Double.class.equals(type))) {
      return new Double(number.doubleValue());
    }
    if ((Integer.TYPE == type) || (Integer.class.equals(type))) {
      return Integer.valueOf(number.intValue());
    }
    if (BigInteger.class.equals(type))
    {
      if ((number instanceof BigDecimal)) {
        return ((BigDecimal)number).toBigInteger();
      }
      if ((number instanceof BigInteger)) {
        return number;
      }
      return BigInteger.valueOf(number.longValue());
    }
    if (BigDecimal.class.equals(type))
    {
      if ((number instanceof BigDecimal)) {
        return number;
      }
      if ((number instanceof BigInteger)) {
        return new BigDecimal((BigInteger)number);
      }
      return new BigDecimal(number.doubleValue());
    }
    if ((Byte.TYPE == type) || (Byte.class.equals(type))) {
      return Byte.valueOf(number.byteValue());
    }
    if ((Short.TYPE == type) || (Short.class.equals(type))) {
      return Short.valueOf(number.shortValue());
    }
    if ((Float.TYPE == type) || (Float.class.equals(type))) {
      return new Float(number.floatValue());
    }
    if (Number.class.equals(type)) {
      return number;
    }
    throw new ELException(MessageFactory.get("error.convert", new Object[] { number, number.getClass(), type }));
  }
  
  public static final Number coerceToNumber(Object obj, Class<?> type)
    throws ELException
  {
    if ((obj == null) || ("".equals(obj))) {
      return coerceToNumber(ZERO, type);
    }
    if ((obj instanceof String)) {
      return coerceToNumber((String)obj, type);
    }
    if (ELArithmetic.isNumber(obj)) {
      return coerceToNumber((Number)obj, type);
    }
    if ((obj instanceof Character)) {
      return coerceToNumber(Short.valueOf((short)((Character)obj).charValue()), type);
    }
    throw new ELException(MessageFactory.get("error.convert", new Object[] { obj, obj.getClass(), type }));
  }
  
  protected static final Number coerceToNumber(String val, Class<?> type)
    throws ELException
  {
    if ((Long.TYPE == type) || (Long.class.equals(type))) {
      try
      {
        return Long.valueOf(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if ((Integer.TYPE == type) || (Integer.class.equals(type))) {
      try
      {
        return Integer.valueOf(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if ((Double.TYPE == type) || (Double.class.equals(type))) {
      try
      {
        return Double.valueOf(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if (BigInteger.class.equals(type)) {
      try
      {
        return new BigInteger(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if (BigDecimal.class.equals(type)) {
      try
      {
        return new BigDecimal(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if ((Byte.TYPE == type) || (Byte.class.equals(type))) {
      try
      {
        return Byte.valueOf(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if ((Short.TYPE == type) || (Short.class.equals(type))) {
      try
      {
        return Short.valueOf(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    if ((Float.TYPE == type) || (Float.class.equals(type))) {
      try
      {
        return Float.valueOf(val);
      }
      catch (NumberFormatException nfe)
      {
        throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
      }
    }
    throw new ELException(MessageFactory.get("error.convert", new Object[] { val, String.class, type }));
  }
  
  public static final String coerceToString(Object obj)
  {
    if (obj == null) {
      return "";
    }
    if ((obj instanceof String)) {
      return (String)obj;
    }
    if ((obj instanceof Enum)) {
      return ((Enum)obj).name();
    }
    return obj.toString();
  }
  
  public static final Object coerceToType(Object obj, Class<?> type)
    throws ELException
  {
    if ((type == null) || (Object.class.equals(type)) || ((obj != null) && (type.isAssignableFrom(obj.getClass())))) {
      return obj;
    }
    if (String.class.equals(type)) {
      return coerceToString(obj);
    }
    if (ELArithmetic.isNumberType(type)) {
      return coerceToNumber(obj, type);
    }
    if ((Character.class.equals(type)) || (Character.TYPE == type)) {
      return coerceToCharacter(obj);
    }
    if ((Boolean.class.equals(type)) || (Boolean.TYPE == type)) {
      return coerceToBoolean(obj);
    }
    if (type.isEnum()) {
      return coerceToEnum(obj, type);
    }
    if (obj == null) {
      return null;
    }
    if ((obj instanceof String))
    {
      if ("".equals(obj)) {
        return null;
      }
      PropertyEditor editor = PropertyEditorManager.findEditor(type);
      if (editor != null)
      {
        editor.setAsText((String)obj);
        return editor.getValue();
      }
    }
    throw new ELException(MessageFactory.get("error.convert", new Object[] { obj, obj.getClass(), type }));
  }
  
  public static final boolean isBigDecimalOp(Object obj0, Object obj1)
  {
    return ((obj0 instanceof BigDecimal)) || ((obj1 instanceof BigDecimal));
  }
  
  public static final boolean isBigIntegerOp(Object obj0, Object obj1)
  {
    return ((obj0 instanceof BigInteger)) || ((obj1 instanceof BigInteger));
  }
  
  public static final boolean isDoubleOp(Object obj0, Object obj1)
  {
    return ((obj0 instanceof Double)) || ((obj1 instanceof Double)) || ((obj0 instanceof Float)) || ((obj1 instanceof Float));
  }
  
  public static final boolean isLongOp(Object obj0, Object obj1)
  {
    return ((obj0 instanceof Long)) || ((obj1 instanceof Long)) || ((obj0 instanceof Integer)) || ((obj1 instanceof Integer)) || ((obj0 instanceof Character)) || ((obj1 instanceof Character)) || ((obj0 instanceof Short)) || ((obj1 instanceof Short)) || ((obj0 instanceof Byte)) || ((obj1 instanceof Byte));
  }
  
  public static final boolean isStringFloat(String str)
  {
    int len = str.length();
    if (len > 1) {
      for (int i = 0; i < len; i++) {
        switch (str.charAt(i))
        {
        case 'E': 
          return true;
        case 'e': 
          return true;
        case '.': 
          return true;
        }
      }
    }
    return false;
  }
}
